package com.xlh.virtualization.controller;

import com.github.pagehelper.PageInfo;
import com.xlh.common.Result;
import com.xlh.util.SizeConverter;
import com.xlh.vo.PageVO;
import com.xlh.virtualization.constant.ContainerStatusEnum;
import com.xlh.dokka.api.DokkaConfigService;
import com.xlh.dokka.api.DokkaContainerService;
import com.xlh.dokka.api.bo.DokkaClusterInfoBO;
import com.xlh.virtualization.domain.ContainerAttr;
import com.xlh.virtualization.domain.ContainerCourseAttr;
import com.xlh.virtualization.domain.ContainerTrainingAttr;
import com.xlh.virtualization.po.ContainerQueryPO;
import com.xlh.virtualization.po.ContainerQuotaUpdatePO;
import com.xlh.virtualization.po.DeletedSwitchUpdatePO;
import com.xlh.virtualization.service.ConfigService;
import com.xlh.virtualization.service.ContainerService;
import com.xlh.virtualization.vo.ContainerCourseVO;
import com.xlh.virtualization.vo.ContainerVO;
import com.xlh.virtualization.vo.ContainerTrainingVO;
import com.xlh.virtualization.vo.HostsResourcesVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;

/**
 * @author cheer
 */
@Api("容器管理")
@RestController
@RequestMapping("/container")
public class ContainerController {

    @Autowired
    private DokkaContainerService dokkaContainerService;

    @Autowired
    private ConfigService configService;

    @Autowired
    private ContainerService containerService;

    @Autowired
    private DokkaConfigService dokkaConfigService;

    @ApiOperation("查询容器集群资源使用情况")
    @GetMapping("/hosts-capacity")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<HostsResourcesVO> queryHostsCapacity() {
        DokkaClusterInfoBO dokkaClusterInfoBO = dokkaContainerService.getClusterInfo();

        double cpuPercent = dokkaClusterInfoBO.getTotalCpus() > 0 ?
                dokkaClusterInfoBO.getUsedCpus() / dokkaClusterInfoBO.getTotalCpus() : 0;

        HostsResourcesVO hostsResourcesVO = HostsResourcesVO.builder()
                .cpu(dokkaClusterInfoBO.getTotalCpus())
                .cpuUsed(Double.parseDouble(String.format("%.2f", dokkaClusterInfoBO.getUsedCpus())))
                .cpuPercent(new DecimalFormat("0.00%").format(cpuPercent))
                .ramTotalKB(dokkaClusterInfoBO.getTotalMemory())
                .ramUsedKB(dokkaClusterInfoBO.getUsedMemory())
                .ramTotal(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getTotalMemory()))
                .ramUsed(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getUsedMemory()))
                .ramFree(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getTotalMemory() -
                        dokkaClusterInfoBO.getUsedMemory()))
                .diskTotalKB(dokkaClusterInfoBO.getTotalDisk())
                .diskUsedKB(dokkaClusterInfoBO.getUsedDisk())
                .diskTotal(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getTotalDisk()))
                .diskUsed(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getUsedDisk()))
                .diskFree(SizeConverter.KBTrim.convert(dokkaClusterInfoBO.getTotalDisk() -
                        dokkaClusterInfoBO.getUsedDisk()))
                .build();

        return Result.success(hostsResourcesVO);
    }

    /*-------   下面6个接口用于 虚拟机管理页面 设置自动销毁容器开关   -------*/

    @ApiOperation("查询系统级别是否开启自动销毁容器")
    @GetMapping("/deleted-switch")
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result<Boolean> queryDeletedSwitch() {
        Boolean switchOn = configService.getContainerDeletedSwitch();
        return Result.success(switchOn);
    }

    @ApiOperation("保存系统级别自动销毁容器开关")
    @PostMapping("/deleted-switch")
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result updateDeletedSwitch(@RequestBody @Valid DeletedSwitchUpdatePO deletedSwitchUpdatePO) {
        configService.updateContainerDeletedSwitch(deletedSwitchUpdatePO.getSwitchOn());
        return Result.success();
    }

    @ApiOperation("查询实验课是否开启自动销毁容器")
    @GetMapping("/deleted-switch/course/{courseId}")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<Boolean> queryDeletedSwitchByCourse(@PathVariable("courseId") Long courseId) {
        Boolean switchOn = configService.getCourseContainerDeletedSwitch(courseId);
        return Result.success(switchOn);
    }

    @ApiOperation("保存实验课的自动销毁容器开关")
    @PostMapping("/deleted-switch/course/{courseId}")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result updateDeletedSwitchByCourse(@PathVariable("courseId") Long courseId,
                                              @RequestBody @Valid DeletedSwitchUpdatePO deletedSwitchUpdatePO) {
        configService.updateCourseContainerDeletedSwitch(courseId, deletedSwitchUpdatePO.getSwitchOn());
        return Result.success();
    }

    @ApiOperation("查询环境实训是否开启自动销毁容器")
    @GetMapping("/deleted-switch/training")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<Boolean> queryDeletedSwitchByTraining() {
        Boolean switchOn = configService.getTrainingContainerDeletedSwitch();
        return Result.success(switchOn);
    }

    @ApiOperation("保存环境实训的自动销毁容器开关")
    @PostMapping("/deleted-switch/training")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result updateDeletedSwitchByTraining(@RequestBody @Valid DeletedSwitchUpdatePO deletedSwitchUpdatePO) {
        configService.updateTrainingContainerDeletedSwitch(deletedSwitchUpdatePO.getSwitchOn());
        return Result.success();
    }

    /*-------   end   -------*/

    /*-------   下面3个接口用于 虚拟机管理页面 展示虚拟机列表   -------*/

    @ApiOperation("分页查询所有容器列表")
    @GetMapping
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result<PageVO<ContainerVO>> queryContainersByPage(
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(required = false, defaultValue = "10") Integer pageSize,
            ContainerQueryPO containerQueryPO) {

        String userInfo = StringUtils.trimToNull(containerQueryPO.getUserInfo());
        List<Integer> status = ContainerStatusEnum.toDatabase(containerQueryPO.getStatus());
        PageInfo<ContainerAttr> pageInfo = containerService.listContainersByPage(pageNum, pageSize, userInfo, status);

        List<ContainerVO> containerVOS = new ArrayList<>();
        for (ContainerAttr containerAttr : pageInfo.getList()) {
            ContainerVO containerVO = ContainerVO.builder()
                    .containerId(containerAttr.getContainerId())
                    .username(containerAttr.getUsername())
                    .userNumber(containerAttr.getUserNumber())
                    .containerName(containerAttr.getContainerName())
                    .imageName(containerAttr.getImageName())
                    .ip(containerAttr.getIp())
                    .status(ContainerStatusEnum.toFrontend(containerAttr.getStatus()))
                    .build();
            containerVOS.add(containerVO);
        }

        PageVO<ContainerVO> pageVO = PageVO.<ContainerVO>builder()
                .pageNum(pageInfo.getPageNum())
                .pageSize(pageInfo.getPageSize())
                .total(pageInfo.getTotal())
                .pages(pageInfo.getPages())
                .content(containerVOS)
                .build();
        return Result.success(pageVO);
    }

    @ApiOperation("分页查询实验课程容器列表")
    @GetMapping("/course/{courseId}")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<PageVO<ContainerCourseVO>> queryCourseContainersByPage(
            @PathVariable("courseId") Long courseId,
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(required = false, defaultValue = "10") Integer pageSize,
            ContainerQueryPO containerQueryPO) {

        String userInfo = StringUtils.trimToNull(containerQueryPO.getUserInfo());
        List<Integer> status = ContainerStatusEnum.toDatabase(containerQueryPO.getStatus());
        PageInfo<ContainerCourseAttr> pageInfo = containerService.listCourseContainersByPage(courseId, pageNum, pageSize,
                userInfo, status);

        List<ContainerCourseVO> containerCourseVOS = new ArrayList<>();
        for (ContainerCourseAttr containerCourseAttr : pageInfo.getList()) {
            ContainerCourseVO containerCourseVO = ContainerCourseVO.courseBuilder()
                    .containerId(containerCourseAttr.getContainerId())
                    .username(containerCourseAttr.getUsername())
                    .userNumber(containerCourseAttr.getUserNumber())
                    .containerName(containerCourseAttr.getContainerName())
                    .imageName(containerCourseAttr.getImageName())
                    .ip(containerCourseAttr.getIp())
                    .status(ContainerStatusEnum.toFrontend(containerCourseAttr.getStatus()))
                    .className(containerCourseAttr.getClassName())
                    .grade(containerCourseAttr.getGrade())
                    .chapterName(containerCourseAttr.getChapterName())
                    .build();
            containerCourseVOS.add(containerCourseVO);
        }

        PageVO<ContainerCourseVO> pageVO = PageVO.<ContainerCourseVO>builder()
                .pageNum(pageInfo.getPageNum())
                .pageSize(pageInfo.getPageSize())
                .total(pageInfo.getTotal())
                .pages(pageInfo.getPages())
                .content(containerCourseVOS)
                .build();
        return Result.success(pageVO);
    }

    @ApiOperation("分页查询环境实训容器列表")
    @GetMapping("/training")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<PageVO<ContainerTrainingVO>> queryTrainingContainersByPage(
            @RequestParam(required = false, defaultValue = "1") Integer pageNum,
            @RequestParam(required = false, defaultValue = "10") Integer pageSize,
            ContainerQueryPO containerQueryPO) {

        String userInfo = StringUtils.trimToNull(containerQueryPO.getUserInfo());
        List<Integer> status = ContainerStatusEnum.toDatabase(containerQueryPO.getStatus());
        PageInfo<ContainerTrainingAttr> pageInfo = containerService.listTrainingContainersByPage(pageNum, pageSize,
                userInfo, status);

        List<ContainerTrainingVO> containerTrainingVOS = new ArrayList<>();
        for (ContainerTrainingAttr containerTrainingAttr : pageInfo.getList()) {
            ContainerTrainingVO containerTrainingVO = ContainerTrainingVO.trainingBuilder()
                    .containerId(containerTrainingAttr.getContainerId())
                    .username(containerTrainingAttr.getUsername())
                    .userNumber(containerTrainingAttr.getUserNumber())
                    .containerName(containerTrainingAttr.getContainerName())
                    .imageName(containerTrainingAttr.getImageName())
                    .ip(containerTrainingAttr.getIp())
                    .status(ContainerStatusEnum.toFrontend(containerTrainingAttr.getStatus()))
                    .trainingName(containerTrainingAttr.getTrainingName())
                    .build();
            containerTrainingVOS.add(containerTrainingVO);
        }

        PageVO<ContainerTrainingVO> pageVO = PageVO.<ContainerTrainingVO>builder()
                .pageNum(pageInfo.getPageNum())
                .pageSize(pageInfo.getPageSize())
                .total(pageInfo.getTotal())
                .pages(pageInfo.getPages())
                .content(containerTrainingVOS)
                .build();
        return Result.success(pageVO);
    }

    /*-------   end   -------*/

    @ApiOperation("删除处于停止状态的容器")
    @PostMapping("/delete")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result deleteContainers(@RequestBody List<Long> containerIds) {
        containerService.deleteExitedContainers(containerIds);
        return Result.success();
    }

    @ApiOperation("查询容器运行最大值")
    @GetMapping("/quota")
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result<Integer> queryContainerQuota() {
        Integer quota = dokkaConfigService.getContainerQuota();
        return Result.success(quota);
    }

    @ApiOperation("保存容器运行最大值")
    @PostMapping("/quota")
    @PreAuthorize("@permissionValidator.isAdmin()")
    public Result updateContainerQuota(@RequestBody @Valid ContainerQuotaUpdatePO containerQuotaUpdatePO) {
        if (dokkaConfigService.saveContainerQuota(containerQuotaUpdatePO.getContainerQuota())) {
            return Result.success();
        } else {
            return Result.error("保存失败");
        }
    }

    @ApiOperation("查询容器运行百分比")
    @GetMapping("/running")
    @PreAuthorize("@permissionValidator.isAdminOrTeacher()")
    public Result<String> queryContainerRunning() {
        Integer quota = dokkaConfigService.getContainerQuota();
        Integer running = dokkaContainerService.getRunningCount();

        String result;
        if (quota == null) {
            result = String.valueOf(running);
        } else {
            result = running + "/" + quota;
        }

        return Result.success(result);
    }
}
